home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / edit / aaem95ma.zip / MACROS.CC < prev    next >
C/C++ Source or Header  |  1995-02-10  |  34KB  |  682 lines

  1. /* This is file MACROS.CC */
  2. #include "em.h"
  3. /*-----*/
  4. /* int ____; long int bp(){__SR(); ____=_bp; __SR(); return ____;}
  5. void BP(){int i=0; long*p=(long int*)bp();
  6. while(p) {i++; p=(long int*)*p;} for(;i>0;i--) fprintf(debug,"  ");} */
  7. /*-----*/
  8. char*CMN="current_macro",keychar,keyseqc[65]; val keyseq(keyseqc,_keyseq);
  9. macro*Record=0; var*globvars=0; int nglobvars=0; val*refaddr(val L);
  10. mark err(0,0); val comment("/*",2),tnemmoc("*/",2);
  11. /*-----*/
  12. KF(obey){val f; switch(T1.n){int i;
  13. case 0: if(record) MOAN("can't call macro which is being recorded"); T1.m=Macro;
  14. case _macro: (*T1.m)(N); return;
  15. default: MOAN("obey() with bad arg or no arg");
  16. case _keyseq: f=T1.keyseq(); if(f.n==_bad) MOAN(f.s);
  17.     if(f.n!=_macro) MOAN("error in obey(): this key is not bound to a macro");
  18.     (*f.m)(N);}}
  19. /*-----*/
  20. KF(macromenu){macro*M; M=macro_menu(); if(!M) MOAN("aborted"); (*M)();};
  21. /*-----*/
  22. KF(namemacro) {int i; macro*M; val nam; if(T2.n!=_macro)
  23. T2=*getk(T2,"type key sequence bound to the macro (ctrlX E for current macro)");
  24. T1.getifn(T1t,"name to bind to the macro?");
  25. for(i=0;i<T1.n;i++) if(!isalnum(T1.s[i])) MOAN("name must be all alphanumeric");
  26. if(T1.n) {if(!isalpha(T1.s[0])) MOAN("name must start with a letter");
  27.     nam=named(T1); if(nam.n!=_unidfname) {
  28.     pr(CW,"'%s' is already a %t",T1.s,nam.typ()); MOAN(CW);}}
  29. if(!play) if(basemi.rec) {setrek(T1,T1.copy()); setrek(T2,keyseq.copy());}
  30. if(T2.n==_subr?T2.f==&obey:0) M=Macro; /* as 'ctrlX E' calls current macro */
  31. else if(T2.n==_macro) M=T2.m;
  32. else {pr(CW,"%s is not bound to a macro",&keyseq); MOAN(CW);}
  33. if(M->name) if(M->name!=CMN) {
  34.     pr(CW,"macro already named '%s': shall I rename it?",M->name);
  35.     if(!yesno(CW)) MOAN("user abort"); delete M->name;}
  36. M->name=copyof(T1);}
  37. /*-----*/
  38. KF(beginmacro) {macro*m; if(play) return; if(record) MOAN("already recording");
  39. Display="start macro"; if(Macro) if(Macro->name==CMN) Macro->name=0;
  40. if(!Macro?:Macro->bound.n?:Macro->name!=0)Macro=new macro();else Macro->empty();
  41. basemi.rec=0; record=Macro; thisstep.f=&_idle; laststep.del(); laststep.clear();
  42. if(T2.n==_keyseq) bindkeymacro(val(1,0),T2);
  43. if(T1.n>0) namemacro(val(1,0),T1,val(record));
  44. else {for(m=macros;m;m=m->next) if(m->name==CMN)
  45.     if(m->bound.n) m->name=0; else delete m; record->name=CMN;}}
  46. /*-----*/
  47. KF(endmacro) {if(play) return;
  48. Display="end macro"; if(!record) MOAN("not recording"); basemi.rec=0;
  49. record->tidy(); record=0; thisstep.f=&_idle; laststep.del(); laststep.clear();}
  50. /*-----*/
  51. KF(repeat) {if(play) {mi->rec=0; (*mi->prevstep)(N.i); return;}
  52. laststep(N.i); if(record)(*record)+=new macstep(kf(&repeat),N); rept=1;}
  53. /*-----*/
  54. KF(prmacro){Macro->print();}
  55. /*-----*/
  56. KF(prmacros) {prvars(globvars); macro*M; for(M=macros;M;M=M->next) M->print();}
  57. /*-----*/
  58. macro*macros=0;
  59. /*-----*/
  60. macstep laststep,thisstep;
  61. val specialchars("\"\\^`",4); /* chars that need \ before as selves in string */
  62. char*rsvword[]={0};
  63. char*Keysort[]={"magicstring","string","unbound","subroutine","macro","char",
  64.   "keyarray","buffer","int","keysequence","reservedword","unidentifiedname",
  65.   "call","bad","uncheckedsubr","function","functionwithinfo","reference","type",
  66.   "float","label",0};
  67. char**keysort=Keysort+2;
  68. /*-----*/
  69. #define Bad(s) ({err=*this; *this=x; return val(s,_bad);})
  70. #define badq(s) if((s).n==_bad) return (s)
  71. #define Badq(s,delendum) if((s).n==_bad) {(delendum).del(); return (s);}
  72. /*-----*//* skip whites and comments */
  73. void mark::Skip(){int n; char*s;
  74. A: n=r->n; s=r->s;
  75. C: if(c<n) {if(s[c]==' '?:s[c]==9) {c++; goto C;}}
  76. else if(r->next) {r=r->next; c=0; goto A;} else return;
  77. if(c>n-2 ?: s[c]!='/' ?: s[c+1]!='*') return; c+=2;
  78. B: if(c<=n-2) if(s[c]=='*') if(s[c+1]=='/') {c+=2; goto A;}
  79. if(c<n) c++; else if(r->next) {r=r->next;c=0;} else MOAN("missing */"); goto B;}
  80. /*-----*/
  81. int mark::thisch(char C){Skip(); int i; if(i=(**this==C)) ++*this; return i;};
  82. /*-----*//* look for s */
  83. int mark::string(val s){Skip(); if(c+s.n>r->n) return 0;
  84.     if(!strncmp(&r->s[c],s.s,s.n)) {c+=s.n; return 1;} return 0;}
  85. /*-----*/
  86. /* int mark::string(val s){Skip(); mark e=here(*this,s);
  87. if(!e.r) return 0; *this=e; return 1;} */
  88. /*-----*//* if n=0, s = 0 or 1 or -> standard empty string, do not delete it */
  89. void val::del(){int i; call*c; switch(n){
  90. case _keyseq: case _unidfname: delete s; break;
  91. case _call: for(i=(c=C)->n-1;i>=0;i--) c->arg[i].del(); delete c; break;
  92. default: if(n>0 ?: magic()) delete s;} n=0; s=0;}
  93. /*-----*/
  94. /* char*Copytext(reg char*t,reg char*s,int n){reg char*u=t+n;
  95. while(t<u) *t++=*s++; return u;} */
  96. /*-----*//* fast move s[0:n-1]=t[0:n-1] */
  97. char* Copytext(char*s,char*t,int n){
  98. asm("pushl %esi"); asm("pushl %edi"); asm("cld");
  99. asm("movl 8(%ebp),%edi"); asm("movl 12(%ebp),%esi"); asm("movl 16(%ebp),%ecx");
  100. asm("rep"); asm("movsb"); asm("movl 8(%ebp),%eax");
  101. asm("popl %edi"); asm("popl %esi");}
  102. /*-----*/
  103. char*copyof(char*s,int n/*=0*/){if(!n) n=strlen(s); if(!s?:!n) return "\000";
  104. char*t=new char[n+1]; Copytext(t,s,n); t[n]=0; return t;}
  105. /*-----*/
  106. char*copyof(const val&s){if(!s.s?:s.n<=0) return "\000";
  107. char*t=new char[s.n+1]; Copytext(t,s.s,s.n); t[s.n]=0; return t;}
  108. /*-----*/
  109. val named(val name){int i; Subr*s; char*w; macro*m; val f; var*v;
  110. if(s=namedsubr(name)) return val(s); /* subr name */
  111. for(m=macros;m;m=m->next) if(m->name) if(name==m->name) return val(m);
  112. for(i=0;w=rsvword[i];i++) if(name==w) return val(i,_rsvword);/* reserved word */
  113. for(i=0;i<255;i++) if(name==altnames[i]) return val(256+i,_char); /*****/
  114. for(i=0;f=keynames[i],f.s;i++) {if(name==f.s) return val(f.n,_char);}
  115. if(name.n==5) if(!strncmp(name.s,"ctrl",4)) return val(name.s[4]&31,_char);
  116. for(i=0;w=funcname[i].name;i++) if(name==w) return val(&funcname[i]);
  117. for(i=-2;w=keysort[i];i++) if(name==w) return val(-i,_type);
  118. for(v=globvars;v;v=v->next) if(name==v->name) return val(v);
  119. if(Record) for(v=Record->vars;v;v=v->next) if(name==v->name) return val(v);
  120. return val(copyof(name),_unidfname);}
  121. /*-----*/
  122. val mark::label(){mark x=*this; Skip(); if(!is_alpha()) Bad("not a name");
  123. int y=c; while(is_alnum()) ++*this; int z=c;
  124. if(!thisch(':')) Bad("no ':' after label"); return named(val(r->s+y,z-y));}
  125. /*-----*/
  126. val mark::name(){mark x=*this; Skip(); if(!is_alpha()) Bad("not a name");
  127. int y=c; while(is_alnum()) ++*this; return named(val(r->s+y,c-y));}
  128. /*-----*/
  129. val mark::number(){int C,i=0; mark x=*this; Skip();
  130. if((C=**this-'0')<0?:C>9) Bad("not a number");
  131. do {c++; i=10*i+C;} while((C=**this-'0')<0?0:C<=9); return val(i);}
  132. /*-----*//* look for text in " " */
  133. val mark::string(){int i,j,k,m=0,magic=0; char C,W[i=lwand(strsize)+1];
  134. mark x=*this; for(i--;i>=0;i--) W[i]=0;
  135. if(thisch('"')) for(j=0;;c++) {
  136.     if(magic) {m=1; magic=0; W[j>>3]|=128>>(j&7);}
  137.     if(j>=strsize-1) Bad("string too long");
  138.     switch(C=**this){
  139.     case '`': magic=1; break; /* next char is magic */
  140.     case '\\': c++; C=**this;
  141.         if(C<'0'?0:C<'8') {k=C-'0'; c++; C=**this; /* \ and 3 octal digits */
  142.             if(C<'0'?0:C<'8') {k=k*8+C-'0'; c++; C=**this;
  143.                 if(C<'0'?0:C<'8') {k=k*8+C-'0'; c++; C=**this;}} c--;CW[j++]=k;}
  144.         else {if(!eol()) CW[j++]=**this; /* code char as itself */} break;
  145.     case '^': c++; CW[j++]=**this&31; break; /* control char */
  146.     case '"': CW[j]=0; c++; if(!m) return val(j?copyof(CW,j):"\000",j);
  147.     k=lwand(j); for(i=0;i<k;i++) CW[j+1+i]=W[i];
  148.     return val(copyof(CW,j+1+k),j|0x80000000); /* magic string */
  149.     case LF: Bad("eol in string");
  150.     default: CW[j++]=C;}}
  151. Bad("not a string");}
  152. /*-----*/
  153. val mark::elem(){char C; mark x=*this; Skip();
  154. val s=number(); if(s.n!=_bad) return s;
  155. s=name();       if(s.n!=_bad) return s;
  156. s=string();     if(s.n!=_bad) return s;
  157. if(eol()) Bad("(part of) expression missing at eol");
  158. if((C=**this)=='(') {c++; s=expr(); badq(s); if(thisch(')')) return s;
  159.     s.del(); Bad("rubbish or eol found instead of )");}
  160. Bad(strncmp(s.s,"not a ",6)?s.s:"not an expression element");}
  161. /*-----*/
  162. typedef struct{char res,Lr,L,Rr,R; char*op; char pr; func*f; char*com;} op_use;
  163. int npriosused;
  164. char*Eq=" =="+1,*Ne=" !="+1,*Ge=" >="+1,*Le=" <="+1,*Gt=" >"+1,*Lt=" <"+1,
  165. *Alc=" ="+1,*Add=" +"+1,*Sub=" -"+1,*Tim=" *"+1,*Div=" /"+1;
  166. char*Ops[]={Alc,Add,Sub,Tim,Div,0}; char op_from_right[27]={[14]1};
  167. op_use *PP[28]={0},ops[]={ /*** keep these entries in priority order ***/
  168. {_int   ,1,_int   ,0,_int   ,Alc,14,_allocate,0},
  169. {_string,1,_string,0,_string,Alc,14,_allocate,0},
  170. {_char  ,1,_char  ,0,_char  ,Alc,14,_allocate,0},
  171. {_int   ,0,_string,0,_string,Eq,  7,_eq,      0},
  172. {_int   ,0,_string,0,_string,Ne,  7,_ne,      0},
  173. {_int   ,0,_int   ,0,_int   ,Eq,  7,_eq,      0},
  174. {_int   ,0,_int   ,0,_int   ,Ne,  7,_ne,      0},
  175. {_int   ,0,_int   ,0,_int   ,Ge,  6,_ge,      0},
  176. {_int   ,0,_int   ,0,_int   ,Le,  6,_le,      0},
  177. {_int   ,0,_int   ,0,_int   ,Gt,  6,_gt,      0},
  178. {_int   ,0,_int   ,0,_int   ,Lt,  6,_lt,      0},
  179. {_int   ,0,_int   ,0,_int   ,Add, 4,_plus,    0},
  180. {_int   ,0, 0     ,0,_int   ,Add, 4,_same,    0},
  181. {_int   ,0,_int   ,0,_int   ,Sub, 4,_minus,   0},
  182. {_int   ,0, 0     ,0,_int   ,Sub, 4,_neg,     0},
  183. {_int   ,0,_int   ,0,_int   ,Tim, 3,_times,   0},
  184. {_int   ,0,_int   ,0,_int   ,Div, 3,_divide,  "rounds towards -inf; x/0 = 0"},
  185. {0,0,0,0,0,0,27,0,0}};
  186. enum{MINUSPR=4};
  187. /**** and secure all func's & subr's against bad values in args ****/
  188. /*-----*//* set up info tables re operators */
  189. void set_up_PP(){op_use*B; int i=0,j=0; if(PP[0]) return;
  190. for(B=ops;B->op;B++) {if(j!=B->pr) j=(PP[i++]=B)->pr; B->op[-1]=i-1;}
  191. PP[npriosused=i]=B;}
  192. /*-----*/
  193. int display_op_uses(){int i,j=1; op_use*P; set_up_PP();
  194. display("operator uses allowed in macros (# = must be a variable)",0,0,Green);
  195. for(i=0;(P=&ops[i])->op;i++) {
  196.     if(P->L) pr(CW,"%s%t%T",P->Lr?"#":" ",P->L,9); else pr(CW,"%T",9);
  197.     pa(CW,"%-2s %s%t%T: returns %t%T: priority %1d %s",P->op,
  198.       P->Rr?"#":" ",P->R,11,P->res,28,npriosused-P->op[-1],P->com?:"");
  199.     if(j==gp_Rows-1) {display("(More)",j,0,Green); get_key(); j=0;}
  200.     display(CW,j++,0,Orange);}
  201. return j;}
  202. /*-----*/
  203. char*mark::op(int p){mark x=*this; Skip();
  204. char*s, a=**this, b=c+1>=r->n?CR:r->s[c+1]; op_use*B,*C=PP[p+1];
  205. for(B=PP[p];B<C;B++) if(a==(s=B->op)[0]) if(!s[1]?1:b==s[1]) goto A;
  206. err=*this; *this=x; return 0; A: c++; if(s[1]) c++; return s;}
  207. /*-----*/
  208. val callop(val L,char*op,val R){
  209. int Lt=L.type(),Rt=R.type(),prio=op[-1]; op_use*B,*C=PP[prio+1]; val t,ar[3];
  210. for(B=PP[prio];B<C;B++) if(op==B->op) if(Lt==B->L) if(Rt==B->R)
  211.   if(B->Lr?L.n==_ref:1) if(B->Rr?R.n==_ref:1) goto OK;
  212. pr(CW,"type error in expr:");
  213. if(L.n) pa(CW," %s %t",   L.n==_ref?"ref":"nonref",Lt);
  214. pa(CW,     " %s %s %t",op,R.n==_ref?"ref":"nonref",Rt);
  215. L.del(); R.del(); return val(CW,_bad);
  216. OK: ar[0]=ff(B->f); ar[1]=L; ar[2]=R; t=call_n(3,B->res,B->pr,B->op,ar);
  217. if(L.known_now()) if(R.known_now()) {val u=t(); t.del(); return u;} return t;}
  218. /*-----*/
  219. val mark::expr(int p/*=0*/){char *Op; val X,*Y,Z; int fr,i; mark x=*this;
  220. set_up_PP(); Skip(); if(eol()) Bad("expression missing at eol");
  221. if(p>=npriosused) return Call();
  222. Op=op(p); X=expr(p+1); badq(X); if(Op) {X=callop(val(),Op,X); badq(X);}
  223. if(fr=op_from_right[PP[p]->pr]) Y=&X.C->arg[2]; else Y=&X;
  224. while(Op=op(p)) {Z=monexpr_upto(p+1); Badq(Z,X); *Y=callop(*Y,Op,Z);
  225.     if(fr) {Badq(*Y,X); Y=&Y->C->arg[2];}} return X;}
  226. /*-----*/
  227. val mark::monexpr_upto(int p){mark x=*this; Skip();
  228. val X; char*op, a=**this, b=c+1>=r->n?CR:r->s[c+1]; op_use*B,*C=PP[p];
  229. for(B=PP[0];B<C;B++) if(a==(op=B->op)[0]) if(!op[1]?1:b==op[1]) goto A;
  230. err=*this; *this=x; return expr(p); A:
  231. c++; if(op[1]) c++; X=monexpr_upto(p); badq(X); X=callop(val(),op,X); return X;}
  232. /*-----*/
  233. static var*declare(char*name,int type){
  234. if(type==_label) return Record->vars=new var(name,type,0,Record->vars);
  235. else if(Record)
  236.     return Record->vars=new var(name,type,Record->nvars++,Record->vars);
  237. else return globvars=new var(name,type,nglobvars++,globvars);}
  238. /*-----*/
  239. int val::type(){int i; short*Z; switch(n) {
  240. default: return magic()?_magic:notstring()?n:_string;
  241. case _ref: return v->type;
  242. case _subr: case _Subr: case _macro: return 0;
  243. case _func: i=(Z=Funcinfo()->args)[0]; return i!=_adinf?i:Z[1];
  244. case _Func: i=(Z=Fn        ->args)[0]; return i!=_adinf?i:Z[1];
  245. case _call: return C->type;}}
  246. /*-----*/
  247. int val::typ(){switch(n) {
  248. default: return magic()?_magic:notstring()?n:_string;
  249. case _ref: return v->type;}}
  250. /*-----*/
  251. int val::checktype(int typ){int m=type(); if(typ==m ?: typ==666) return 1;
  252. switch(typ){
  253. case _magic: return m==_string;
  254. case _keyseq: return m==_char;
  255. case _char: return m==_string;
  256. case _label: if(m==_unidfname) {*this=named(s); /* already thus declared? */
  257.     if(n==_unidfname) {n=_ref; v=declare(copyof(s),_label);} return 1;}}
  258. return 0;}
  259. /*-----*/
  260. val val::convto(int t){int f=typ(); val v; if(t==f) return *this; switch(f){
  261. case _string: if(t==_magic?:t==_char) return *this;
  262. case _char: if(t==_keyseq) return *this; break;}
  263. pr(CW,"can't convert %t to %t",f,t); MOAN(CW); return val();}
  264. /*-----*/
  265. int val::known_now(){
  266. switch(n){case _subr: case _macro: case _call: case _Subr:
  267. case _func: case _Func: case _ref: return 0;} return 1;};
  268. #define MoaN(s) ({err=*this; *this=x; Moan=s; goto BAD;})
  269. /*-----*/
  270. val mark::Call(){
  271. val t,u,args[32],f,g,N,Arg[4],*z; int i=0,j,k,l,m,n,se; mark x=*this;
  272. char*ac; call*C; mark q[33]; static short MA[]={_int,0}; jmp_buf*oldbad,failed;
  273. short*a; Skip(); q[0]=*this; n=0; if(eol()) MoaN("matter missing at eol");
  274. t=elem(); badq(t); args[0]=t; q[1]=*this; n=1;
  275. if(thisch('(')) if(!thisch(')')) {
  276.     do {u=expr(); q[i=n+1]=*this; if(u.bad()) {Moan=u.s; goto BAD;}
  277.     if(n>31) {u.del(); MoaN("> 31 args");}
  278.     args[n++]=u;} while(thisch(','));
  279.     if(!thisch(')')) MoaN("rubbish after arg");}
  280. switch(t.n) {
  281. case _Subr: a=t.S->args-1;
  282.     Arg[1]=val(1,0); Arg[2]=val(); Arg[3]=val();
  283.     for(i=j=1;(k=a[j])?i<n:0;j++) if(args[i].checktype(k)) Arg[j]=args[i++];
  284.     if(i!=n) goto BADARG;
  285.     Arg[0]=kf(t.S->f); return val(call_n(4,0,0,t.S->name,Arg));
  286. case _Func: a=t.Fn->args; if(se=(a[0]==_adinf)) a++;
  287.     for(i=j=1;i<n;i++) {
  288.     if(!a[j]) MoaN("too many args");
  289.     if(!args[i].checktype(a[j])) {a++; goto BADARG;}
  290.     if(a[j+1]!=_adinf) j++;}
  291.     k=a[0]; if(se) goto Z;
  292.     for(i=1;i<n;i++) if(!args[i].known_now()) goto Z; /* can I find value now?*/
  293.     oldbad=bad; bad=&failed; if(setjmp(*bad)) goto BADD;
  294.     t=t.Fn->f(n,args); for(i=0;i<n;i++) args[i].del(); bad=oldbad; return t;
  295. BADD: err=x; bad=oldbad; return val(Moan,_bad);
  296. /* case _func: k=Funcinfo()->args[0]; */
  297. Z:  return val(call_n(n,k,0,t.Fn->name,args));
  298. case _macro: i=1; N=val(1,0); if(i<n) if(args[i].checktype(_int)) N=args[i++];
  299.     if(i!=n) {a=MA; goto BADARG;}
  300.     Arg[0]=kf(&obey); Arg[1]=N; Arg[2]=t; Arg[3]=val();
  301.     return val(call_n(4,0,0,"obey",Arg));
  302. case _type: if(n!=1) {pr(CW,"'%t' should not have args",t.i); i=1; MoaN(CW);}
  303.     return t;
  304. default: if(n==1) return t; /* has no args so isn't a call */
  305.     pr(CW,"a %t can't be a call base",t.n); i=0; MoaN(CW);}
  306. BADARG:
  307. if(a[1]) {pr(CW,"args %sshould be:",t.n==_Func?"":"(can be omitted) ");
  308.     for(l=1;k=a[l];l++) {if(k==_adinf) {pa(CW,"s"); /* plural */ break;}
  309.     else pa(CW," %t",k);}}
  310. else pr(CW,"should have no args");
  311. ac=CW+strlen(CW);
  312. if(n) {pa(CW," args are:"); for(l=1;l<n;l++) pa(CW," %t",args[l].type());}
  313. else pa(CW," has no args");
  314. *ac=0; Display=CW; Moan=ac+1;
  315. BAD: err=q[i]; for(i=0;i<n;i++) args[i].del(); *this=x; return val(Moan,_bad);;}
  316. #define Bad(s) ({err=*this; *this=x; return val(s,_bad);})
  317. /*-----*/
  318. char*not_a_decl="not a decl";
  319. val mark::decl(){val args[32]; int i=0,n=0; mark q[33],x=*this; Skip();
  320. if(eol()) return val(); q[0]=*this; args[0]=name(); q[1]=*this; n=1;
  321. if(args[0].n!=_type?: (Skip(), !is_alnum())) {Moan=not_a_decl; goto BAD;}
  322. do {val u=name(); q[i=n+1]=*this;
  323.     if(u.bad()) {Moan="bad name in decl"; goto BAD;}
  324.     if(n>31) {u.del(); Moan="declaration has > 31 args"; goto BAD;}
  325.     if(u.n!=_unidfname) {
  326.     u.print(Moan=CW); pa(CW," is already a %t",u.typ()); u.del(); goto BAD;}
  327.     args[n++]=u;} while(thisch(','));
  328. return val(call_n(n,0,0,keysort[-args[0].i],args));
  329. BAD: err=q[i]; for(i=0;i<n;i++) args[i].del(); *this=x; return val(Moan,_bad);;}
  330. /*-----*/
  331. call*call_n(int n,int type,int pr,char*name,val*a){
  332. call*c=(call*)myalloc(sizeof(call)+(n-1)*sizeof(val));
  333. c->n=n; c->type=type; c->pr=pr; c->name=name;
  334. int i; val*b=c->arg; for(i=0;i<n;i++) b[i]=a[i]; return c;}
  335. /*-----*/
  336. KF(_idle){}
  337. /*-----*/
  338. static macstep*jump=0;
  339. KF(go_to){if(T1.n==_ref) if(T1.v->type==_label) jump=(macstep*)(T1.v->offset);}
  340. /*-----*/
  341. KF(If){} /* 'if' is handled elsewhere */
  342. /*-----*/
  343. subr*subrcalled(val V){if(V.n==_call) V=V.C->arg[0]; switch(V.n){
  344. case _subr: return V.f; case _Subr: return V.S->f; default: return 0;}}
  345. /*----- is val a char or the name of a (char or special key)? */
  346. int val::charval(){
  347. if(n==1) return s[0]; /* string with one char */
  348. if(n==_char) return i;
  349. if(n<1) return -1; int j;
  350. if(n<4) for(j=0;j<255;j++) if(*this==altshortnames[j]) return j+256; return -1;}
  351. /*-----*/
  352. void val::expandkeyseq(char*K,int plain/*=0*/){int e,j,k,l,p; char *x,*S=s,a[3];
  353. if(n==_char) if(S=a,i&~255) {a[0]=3; a[1]=0; a[2]=i&255;} else {a[0]=2; a[1]=i;}
  354. else if(n!=_keyseq) MOAN("BUG: expandkeyseq bad arg"); p=(byte)S[0];
  355. if(plain) {for(e=1,K[0]=0;e<p;e++) if(S[e]) {
  356.     strcat(K,keyname((byte)S[e],e>1?!S[e-1]:0)); strcat(K," ");}
  357.     e=strlen(K); K[e-1]=0; return;}
  358. strcpy(K,"keyseq("); k=6;
  359. for(e=1;e<p;e++) if(S[e]) {x=keyname((byte)S[e],e>1?!S[e-1]:0);
  360.     if(x[1]) {strcat(K,x); k=strlen(K);}
  361.     else {j=(byte)*x;
  362.     K[k++]='"'; if(j=='"'?:j=='\\') K[k++]='\\'; K[k++]=j; K[k++]='"';}
  363.     K[k++]=','; K[k]=0;}
  364. K[k-1]=')'; K[k]=0;}
  365. /*-----*/
  366. #undef Bad
  367. /*----- translate buffer to macro */
  368. void translate(buffer*BB){int i,j,t,n,nargs; buffer*BBB=B; macro*m;
  369. val *arg,*K=0,N,S,T,T1,T2,U,V,W; Record=0; char*ac,spec; mark par,x,y; subr*Z;
  370. jmp_buf*oldbad=bad,failed; bad=&failed; if(setjmp(*bad)) goto BAD;
  371. /* if(record) {Moan="can't read in macros while recording a macro"; goto BAD;}*/
  372. T=val(); if(B!=BB) BB->go_to();
  373. for(i=0;i<basemi.nvars;i++) basemi.stack[i].del();
  374. delete globvars; delete basemi.stack;
  375. globvars=0; basemi.stack=0; nglobvars=basemi.nvars=0; par=mark(B->text.next,0);
  376. NEXTINSTR: B->dot=par; B->dotcc=-1; B->display();
  377. x=par; par.Skip(); err=par; spec=0;
  378. if(par.eof()) {if(B!=BBB) BBB->go_to(); bad=oldbad; Moan=0; return;} y=par;
  379. if(Record) if(T=par.label(), T.n!=_bad) {var*v;
  380.     if(T.n==_unidfname) {T.n=_ref; T.v=declare(copyof(T.s),_label);}
  381.     if(T.n==_ref) {*Record+=new macstep(T);
  382.         if(T.v->type==_label) {
  383.             if(T.v->offset) {Moan="label defined twice"; goto BAD;}
  384.             T.v->offset=(long int)Record->last; goto NEXTINSTR;}
  385.         else {pr(Moan=CW,"this label is already declared as a %t",T.v->type);
  386.             goto BAD;}}
  387.     else {pr(Moan=CW,"a %t can't be a label",T.n); goto BAD;}}
  388. T=par.decl(); if(T.n!=_bad ?: T.s!=not_a_decl) goto A; Moan=0; par=y;
  389. spec=par.thisch('#'); T=par.expr(); if(T.n==_bad) {Moan=T.s; goto BAD;}
  390. A: if(!par.thisch(';')) {
  391.     err=par; par=x; T.del(); Moan="rubbish after command"; goto BAD;}
  392. if(spec) switch(T.n) {
  393. default: pr(Moan=CW,"%t after '#'",T.typ()); goto BAD;
  394. case _bad: Moan=T.s; goto BAD;
  395. case _subr: Z=T.f; goto Y;
  396. case _Subr: Z=T.S->f; Y: N=val(1,0); T1=val(); T2=val(); goto Z;
  397. case _call: switch(U=(arg=T.C->arg)[0], Z=U.f, U.n) {
  398.     case _Subr: U=kf(Z=U.S->f);
  399.     case _subr: N=arg[1]; T1=arg[2]; T2=arg[3];
  400. Z:    if(Z==&unbindkey) {if(T1.n) if(K=&T1.keyseq()) K->unbind(); K=0;}
  401.     else if(Z==&buffer_) {if(T1.n) buffer_(N,T1,T2); BB->go_to();}
  402.     else if(Z==&beginmacro) { /* new macro named T1 bound to key T2 */
  403.         if(T2.n) {if(Moan=(K=&T2.keyseq())->moanifbound(T2,0)) goto BAD;
  404.         (Record=new macro())->bound=keyseq.copy();
  405.         if(T1.n>0) namemacro(val(1,0),T1,val(Record)); *K=*Record;}
  406.         else {K=0; Record=new macro();
  407.         if(T1.n>0) namemacro(val(1,0),T1,val(Record));
  408.         else {for(m=macros;m;m=m->next) if(m->name==CMN)
  409.             if(m->bound.n) m->name=0;
  410.             else if(Macro!=record) delete m;
  411.             Record->name=CMN; record=0; Macro=Record;}}}
  412. /* unnamed & unbound macro terminates and replaces current macro */
  413.     else if(Z==&endmacro) {Record=0; K=0; break;}
  414.     else {Moan="wrong subroutine after '#'"; goto BAD;} break;
  415.     default: pr(Moan=CW,"call of a %t after '#'",U.n); goto BAD;}
  416.     break;}
  417.  
  418. else switch(T.n) {
  419. case _bad: Moan=T.s; goto BAD;
  420. case _rsvword: pr(Moan=CW,"'%s' used wrongly",rsvword[T.i]); goto BAD;
  421. case _unidfname: pr(Moan=CW,"'%s' not known",T.s); goto BAD;
  422. default: pr(Moan=CW,"this is a %t",T.typ()); goto BAD;
  423. case _Subr: case _subr: case _Func: case _macro: *Record+=new macstep(T); break;
  424. case _call: U=(arg=T.C->arg)[0];
  425.     if(U.n!=_type)if(!Record){Moan="instruction not in a macro body"; goto BAD;}
  426.     switch(U.n) {
  427.     case _type: switch(U.i) {
  428.     default: Moan="can't declare this type of variable yet"; goto BAD;
  429.     case _int: case _string: for(i=1;i<T.C->n;i++) {W=T.C->arg[i];
  430.         if(W.n==_unidfname) W=named(val(W.s)); if(W.n!=_unidfname) {
  431.         W.print(Moan=CW); pa(CW," is already a %t",W.typ()); goto BAD;}
  432.         declare(W.s,U.i);}} break;
  433.     case _Subr: case _subr: *Record+=new macstep(U,arg[1],arg[2],arg[3]);
  434.         break;
  435.     case _macro: *Record+=new macstep(U,arg[1]); break;
  436. /*    case _macro: *Record+=new macstep(kf(&obey),arg[1],U); break;*/
  437.     case _Func: case _func: *Record+=new macstep(T); T=val(); break;
  438.     default: pr(Moan=CW,"call base is a %t",U.typ()); goto BAD;}}
  439. goto NEXTINSTR;
  440. BAD: bad=oldbad; BB->go_to(); T.del(); B->dotcc=-1; err.c<?=err.r->n;B->dot=err;
  441. if(Record) {if(K) *K=val(); delete Record; Record=0;} MOAN(Moan);}
  442. /* unbind & delete incomplete macro */
  443. /*-----*/
  444. #define __(name,Name,args) {&name,0,0,0,Name,args}
  445. val __idle(int i,val*v){return val();}
  446. Func anonfunc=__(__idle,"###",0); Subr anonsubr=__(_idle,"@@@",0);
  447. /*-----*/
  448. Subr*val::Subrinfo(){reg int i; reg char*s;
  449. for(i=0;s=subrname[i].name;i++) if(f==subrname[i].f) return &subrname[i];
  450. return &anonsubr;}
  451. /*-----*/
  452. Func*val::Funcinfo(){reg int i; reg char*s;
  453. for(i=0;s=funcname[i].name;i++) if(fn==funcname[i].f) return &funcname[i];
  454. return &anonfunc;}
  455. /*-----*/
  456. char*val::Subrname(){return f ?Subrinfo()->name:"<<unknown subroutine>>";}
  457. char*val::Funcname(){return fn?Funcinfo()->name:"<<unknown function>>";}
  458. /*-----*/
  459. char*chname(int c){static char ct[3]="^ ",sc[3]="\\ ",cc[2]=" ",cs[5]="\\000";
  460. c&=255; if(c>=128) {pr(cs,"\\%03o",c); return cs;}
  461. if(specialchars>>c) {sc[1]=c; return sc;}
  462. if(c<32) {ct[1]=c+64; return ct;} cc[0]=c; return cc;}
  463. /*----- if ')' last before B->dot, replace it with ',', else insert '(' */
  464. void start_an_arg(){int i=!B->dot.c?0:B->dot.r->s[B->dot.c-1]==')';
  465. if(i) B->dot.bs(); *B+=i?',':'(';}
  466. /*-----*/
  467. val val::copy(){switch(n){
  468. default: if(magic()) {int i=n&0x7fffffff; return val(copyof(s,i+1+lwand(i)),n);}
  469.     if(n<=0) return *this; return val(copyof(s,n),n);
  470. case _keyseq: return val(copyof(s,(byte)s[0]),n);
  471. case _unidfname: return val(copyof(s,0),n);}}
  472. /*-----*/
  473. void prvars(var*V){int i,j; var*v; int Nt[_typeend-_typebeg],*nt=Nt-_typebeg;
  474. for(i=_typebeg;i<_typeend;i++) nt[i]=0;
  475. for(j=0,v=V;v;v=v->next) {nt[v->type]++; j++;}
  476. if(j) for(i=_typebeg;i<_typeend;i++) if(nt[i]) if(i!=_label) {
  477.     pb("%t ",i); for(v=V;v;v=v->next) if(v->type==i) pb("%s,",v->name);
  478.     B->dot.bs(); *B+=";\n";}}
  479. /*-----*/
  480. void macro::print(){int i; macstep *A,*C; char*N=name?:CMN; *B+="#beginmacro";
  481. if(bound.n) if(N!=CMN) pb("(%S,%K)",N,&bound); else pb("(%K)",&bound);
  482. else if(N!=CMN) pb("(%S)",N); *B+=';'; newline(); prvars(vars);
  483. for(A=text;A;A=A->next) A->print(); *B+="#endmacro;\n";}
  484. /*-----*/
  485. void prsubrargs(val f,val N,val T1,val T2){f.print();
  486. if(N.n ?:(uns int)N.s >=4096) {start_an_arg();  N.print(); *B+=')';}
  487. if(T1.n?:(uns int)T1.s>=4096) {start_an_arg(); T1.print(); *B+=')';}
  488. if(T2.n?:(uns int)T2.s>=4096) {start_an_arg(); T2.print(); *B+=')';}}
  489. /*-----*/
  490. void macstep::print(){int i,j,n=0; char *s; val v; switch(f.n){
  491. case _Subr: if(f.S->f==&_idle) return; break;
  492. case _subr: if(f.f==&_idle) return; break;
  493. case _macro: if(f.m->name) break; v=kf(obey);
  494.     macstep(v,N,f.m->bound,val()).print(); return;
  495. default: if(!f.magic()) if(f.notstring()) break;
  496. case _char: case _keyseq: case _int: pb("*** "); break;
  497. case _rsvword: pb("*** reserved: "); break;
  498. case _ref: pb("%s: ",f.v->name); return;}
  499. prsubrargs(f,N,T1,T2); *B+=';'; newline();}
  500. /*-----*/
  501. void val::print(char*Z/*=(char*)_buffer*/,int pr/*=1000*/){
  502. int j,k,p; val*a; char*z;
  503. if(this) switch(n){
  504. default: if((j=type())<=0) p_r(Z,"<<<%t>>>",j); else p_r(Z,"%v",this); break;
  505. case 0: if(!s) p_r(Z,"%s","<<<null>>>"); else p_r(Z,"\"\""); break;
  506. case _type: p_r(Z,keysort[-i]); break;
  507. case _keyseq: p_r(Z,"%K",this); break;
  508. case _Subr: p_r(Z,S->name); break;
  509. case _subr: p_r(Z,Subrname()); break;
  510. case _Func: p_r(Z,Fn->name); break;
  511. case _func: p_r(Z,Funcname()); break;
  512. case _macro: if(m->name) p_r(Z,m->name);
  513.     else if(m->bound.n) p_r(Z,"%K",&m->bound);
  514.     else p_r(Z,"<<<unnamed unbound macro>>>"); break;
  515. case _char: if(i<256) p_r(Z,"\"%s\"",chname(i));
  516.     else if(z=altnames[i&255]) p_r(Z,"%s",z);
  517.     else p_r(Z,"<<<char 0 %1d>>>",i&255); break;
  518. case _buffer: p_r(Z,"<<<buffer \"%s\">>>",b->name); break;
  519. case _int: z="%1d"; if(i<0) if(pr<=MINUSPR) z="(%1d)"; p_r(Z,z,i); break;
  520. case _rsvword: p_r(Z,"%s",rsvword[i]); break;
  521. case _unidfname: p_r(Z,"<<<unknown word: %s>>>",s); break;
  522. case _bad: p_r(Z,"<<<bad parsing: %s>>>",s); break;
  523. case _call: if(!C) break; p=C->n; a=C->arg; if(!a) break;
  524.     if(a[0].n==_func) {if(pr) goto EXPR; else p_r(Z,C->name);}
  525.     else if(a[0].n==_subr) {prsubrargs(a[0],a[1],a[2],a[3]); break;}
  526.     else a[0].print();
  527.     if(p<2) break;
  528.     for(j=1;j<p;j++) {start_an_arg(); a[j].print(); p_r(Z,")");} break;
  529. EXPR: p=C->pr; j=1; k=0;
  530.     if(op_from_right[p]) {j=0; k=1;} if(pr<=p) p_r(Z,"(");
  531.     if(a[1].n?:a[1].i) a[1].print(Z,p+j); p_r(Z,C->name); a[2].print(Z,p+k);
  532.     if(pr<=p) p_r(Z,")"); break;
  533. case _ref: p_r(Z,v->name); break;}}
  534. /*-----*/
  535. void macstep::del(){f.del(); N.del(); T1.del(); T2.del(); clear();}
  536. /*----- remove pointers to buffers & macros which are being deleted */
  537. void del_every(val f,keyarray&ka){int i,n=ka.n; val*F=ka.a;
  538.   for(i=0;i<n;i++,F++) if(F->n==_keyarray) {del_every(f,*F->k); return;}
  539.   else if(f==*F) F->n=F->i=0;}
  540. void del_every(val f,val&m){val*a; int i,n; /* look in macro args */
  541.   if(m.n==_call) {a=m.C->arg; n=m.C->n; for(i=0;i<n;i++) del_every(f,*a++);}
  542.   else if(f==m) m.n=m.i=0;}
  543. void del_every(val f,macstep*M){for(;M;M=M->next){del_every(f,M->f);
  544.   del_every(f,M->N); del_every(f,M->T1); del_every(f,M->T2);}}
  545. void del_every(val f){macro*m; for(m=macros;m;m=m->next) del_every(f,m->text);
  546.   del_every(f,&thisstep); del_every(f,&laststep); del_every(f,keys);}
  547. /*-----*/
  548. macro::~macro(){macro**I; del_every(val(this));
  549. for(I=&(macros);*I;I=&((*I)->next)) if(*I==(this)) {*I=(*I)->next; break;}
  550. empty();};
  551. /*----- delete all macsteps in macro */
  552. void macro::empty(){macstep *A,*B; if(bound.n) delete bound.s; delete vars;
  553. if(name!=CMN) delete name; for(B=text;A=B;B=A->next) delete A; text=last=0;}
  554. /*----- macro+=macstep : append macstep to macro */
  555. void macro::operator+=(macstep*m){if(play?:!this) return;
  556. if(last) last->next=m; else text=m; (last=m)->next=0;}
  557. /*----- tidy macro */ /* chain up insert/overlay char macsteps */
  558. void macro::tidy(){int i,n; subr*u; macstep*M,*N,*P; char*s; if(!text) return;
  559. for(M=text;M;M=M->next) if(M->T1.n==_char) if(M->N.i==1)
  560.   if((u=M->f.f)==&insert?:u==&overlay?:u==&nomove){/* chain chars into string */
  561.     for(n=1,N=(P=M)->next;;P=N,N=N->next,n++)
  562.       if(!N ?: N->T1.n!=_char ?: N->f.f!=u ?: N->N.i!=1) break;
  563.     if(N) if(N->f.f==&repeat) n--; if(n<=1) continue;
  564.     s=new char[n+1]; s[n]=0; s[0]=M->T1.i;
  565.     for(i=1,N=M->next;i<n;) {s[i++]=N->T1.i; P=N->next; delete N; N=P;};
  566.     M->T1=val(s,n); M->next=N;}
  567. last=0; for(M=text;M;M=M->next) if(M) last=M;}
  568. /*-----*/
  569. macro *record=0,*Macro=0; int macdepth; macstep _lazy(kf(&_idle));
  570. /*-----*/
  571. static void G(){int i; if(!basemi.stack) {basemi.stack=new val[nglobvars];
  572.     for(i=0;i<nglobvars;i++) basemi.stack[i]=val();}}
  573. /*-----*/
  574. void macro::operator()(val N/*=val(1,0)*/,int r/*=0*/){int nn=N.n==_int?N.i:1;
  575. val *p; int i,n,b=0; macstep*A; macrinfo MI,*oldmi=mi; mi=&MI; G();
  576. jmp_buf*oldbad=bad,failed; bad=&failed; if(setjmp(*bad)) {b=1; goto BAD;}
  577. if(n=nvars) {p=mi->stack=new val[mi->nvars=n]; for(i=0;i<n;i++) p[i]=val();}
  578. if(macdepth++>16) {Moan="macro calls >16 deep"; goto BAD;}
  579. for(i=0;jump=0,Breakin()?0:i<nn;i++)
  580.   for(A=text,MI.prevstep=&_lazy;A;A=jump?:A->next){
  581.     MI.rec=1; jump=0; (*A)(); mi=&MI;
  582.     if(MI.rec) MI.prevstep=A; if(Breakin()) goto BAD;}
  583. BAD: for(i=0;i<mi->nvars;i++) mi->stack[i].del();
  584. macdepth--; mi=oldmi; bad=oldbad; if(b) MOAN(Moan);}
  585. /*-----*//*** be careful in case a loose macstep is a &repeat ***/
  586. void macstep::operator()(int p/*=1*/){int i; subr*S;
  587. prevobtype=obtype; obtype=ob_other; G();
  588. switch(f.n) {default: break;
  589. case _func: case _Func: case _call: for(i=0;i<p;i++) f(); break;
  590. case _Subr: S=f.S->f; goto SS; case _subr: S=f.f;
  591. SS: if(S==If) for(i=0;i<p;i++) N().i?T1():T2();
  592.     else for(i=0;i<p;i++) S(N(),T1(),T2()); break;
  593. case _macro: for(i=0;Breakin()?0:i<p;i++) (*f.m)(N);} B->dotcc=-1;}
  594. /*-----*/
  595. val val::operator()(){int j,N; val *V,*arg,*lhs; subr*sub; macro*M; G();
  596. switch(n){default: return*this;
  597. case _macro: (*m)(); return val();
  598. case _subr:    (*f)(val(1,0),val(),val()); return val();
  599. case _Subr: (*S->f)(val(1,0),val(),val()); return val();
  600. case _Func: return Fn->f(1,this);
  601. case _func: return fn(1,this);
  602. case _ref: if(v->type==_label) return*this;
  603.     lhs=refaddr(*this); return lhs?*lhs:val();
  604. case _call:;}
  605. switch((arg=C->arg)[0].n){
  606. default: pr(CW,"tried to call a %t",arg[0].type()); MOAN(CW);
  607. case _macro: M=arg[0].m; (*M)(arg[1]); break;
  608. case _subr: sub=arg[0].f; goto F;
  609. case _Subr: sub=arg[0].S->f;
  610. F:  if(sub==If) arg[1]().i?arg[2]():arg[3]();
  611.     else (*sub)(arg[1](),arg[2](),arg[3]()); break;
  612. case _Func: return arg[0].Fn->f(C->n,arg);
  613. case _func: return arg[0].fn   (C->n,arg);
  614. case _type: pr(CW,"illegal call of '%t'",i); MOAN(CW);}
  615. return val();}
  616. /*-----*/
  617. macro*macro_menu() {int i,n; macro*mac,*M; for(n=0,M=macros;M;M=M->next) n++;
  618. if(play) MOAN("BUG: obeyed macromenu from macro"); if(!n) return 0;
  619. mousestate ms; ms=Jerry; Jerry.mc=1; Jerry.range(n,80); Jerry.move(0,0);
  620. int j=0,k,m,w=gp_Rows-2,c=0; char*s; macro*macs[n];
  621. for(i=0,M=macros;M;M=M->next,i++) macs[i]=M;
  622. E: k=w/2; k=j<w?0:((j-w/4)/k)*k; display("MACROS DEFINED",0,0,Magenta+8);
  623. for(i=k;i<n;i++) {if(i-k>=w) break; s=macs[i]->name; *CW=0;
  624.     if(macs[i]->bound.n) pr(CW," %K",&macs[i]->bound); if(s) pa(CW," `%s'",s);
  625.     if(!*CW) pr(CW,CMN); CW[gp_Cols]=0; display(CW,i-k+1,0,Magenta+8);}
  626. for(i=(w<?n)-1;i>=n-k;i--) display(" ",i,0,Magenta+8);
  627. display("(\030\031 move, RET chooses, alt_end quits)", (w<?n)+1,0,Magenta+8);
  628. A: i=k; k=w/2; k=j<w?0:((j-w/4)/k)*k; if(i!=k) goto E; m=j-k+1;
  629. scr(m,0)=sch(2,White); switch(c=getkey()) {
  630. case -mousemove: j=Jerry.y; break;
  631. case -downarrow: j=(j+1  )%n; break;
  632. case -uparrow:   j=(j-1+n)%n; break;
  633. case -alt_end: case -mbutton: case -rbutton: Jerry=ms; return 0;
  634. case CR: case -lbutton: Jerry=ms; return macs[j];}
  635. scr(m,0)=sch(' ',White); if(c!=-mousemove) Jerry.move(0,j); goto A;}
  636. /*-----*/
  637. /* enum {_unbound=0,_subr=-1,_macro=-2,_char=-3,_keyarray=-4,_buffer=-5,_int=-6,
  638. _keyseq=-7,_rsvword=-8,_unidfname=-9,_call=-10,_bad=-11,_Subr=-12,_func=-13,
  639. _Func=-14}; */
  640. /*-----*/
  641. val*refaddr(val L){int i; if(L.n!=_ref) return 0;
  642. return &(((i=L.v->offset)&0x80000000)?basemi:*mi)[i&0x7fffffff];}
  643. /*-----*/
  644. FN(_allocate){val*lhs=refaddr(arg[1]),x=arg[2]().copy();
  645. if(lhs) {lhs->del(); *lhs=x;} return x;}
  646. /*-----*/
  647. FN(_andthen){if(macdepth++>16) MOAN("macro calls >16 deep");
  648. macstep prev(_lazy); int i; macrinfo MI,*oldmi=mi; mi=&MI; mi->prevstep=&prev;
  649. for(i=1;i<n;i++) {MI.rec=1; arg[i](); mi=&MI; if(MI.rec) prev.f=arg[i];}
  650. macdepth--; mi=oldmi; return val();}
  651. /*-----*/
  652. int byteq(char*a,char*b,int n){reg byte *s=(byte*)a,*t=(byte*)b,*u=s+n;
  653.     while(s<u) if(*s++!=*t++) return 0; return 1;}
  654. int streq(val a,val b){if(a.n!=b.n?:a.n<0) return 0; return byteq(a.s,b.s,a.n);}
  655. /*-----*//* treat val() = undefined as 0 */
  656. #define EA val a=arg[1](),b=arg[2]();
  657. FN(_eq    ){EA; return a.n==_int ? a.i == b.i :  streq(a,b);}
  658. FN(_ne    ){EA; return a.n==_int ? a.i != b.i : !streq(a,b);}
  659. FN(_ge    ){return arg[1]().i >= arg[2]().i;}
  660. FN(_le    ){return arg[1]().i <= arg[2]().i;}
  661. FN(_gt    ){return arg[1]().i > arg[2]().i;}
  662. FN(_lt    ){return arg[1]().i < arg[2]().i;}
  663. FN(_plus  ){return arg[1]().i + arg[2]().i;}
  664. FN(_minus ){return arg[1]().i - arg[2]().i;}
  665. FN(_times ){return arg[1]().i * arg[2]().i;}
  666. FN(_divide){val b=arg[2](); return b.i?arg[1]().i/b.i:0;} /* x/0 = 0 here */
  667. FN(_same  ){return   arg[2]().i;}
  668. FN(_neg   ){return - arg[2]().i;}
  669. /*-----*/
  670. FN(currentbuffer){return val(B->name?:".no file.");}
  671. /*-----*/
  672. FN(keyseq_){int i,j,m; for(i=j=1;i<n;i++) {
  673.     if((m=arg[i]().charval())<0) MOAN("bad keyseq arg");
  674.     if(m>255) keyseqc[j++]=0; keyseqc[j++]=m&255;
  675.     if(j>61) MOAN("keyseq with too many args");}
  676. keyseqc[0]=j; return keyseq.copy();}
  677. /*-----*/
  678. /* In run time, FN's return value, or val() (= void)), or val(<string>,_bad).
  679. In compile time, ditto, or val(type,_bad) = "delivers that type but I can't
  680. find its value now". val(_bad,_bad) = "ditto but I can't tell now what type
  681. it delivers". val(1,_bad) = "ditto but delivers string". */
  682.